/*
** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/

#ifndef lvm_h
#define lvm_h


#include "ldo.h"
#include "lobject.h"
#include "ltm.h"


#if !defined(LUA_NOCVTN2S)
#define cvt2str(o)  ttisnumber(o)
#else
#define cvt2str(o)	0	/* no conversion from numbers to strings */
#endif


#if !defined(LUA_NOCVTS2N)
#define cvt2num(o)  ttisstring(o)
#else
#define cvt2num(o)	0	/* no conversion from strings to numbers */
#endif


/*
** You can define LUA_FLOORN2I if you want to convert floats to integers
** by flooring them (instead of raising an error if they are not
** integral values)
*/
#if !defined(LUA_FLOORN2I)
#define LUA_FLOORN2I    0
#endif


#define tonumber(o, n) \
  (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))

#define tointeger(o, i) \
    (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))

#define intop(op, v1, v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))

#define luaV_rawequalobj(t1, t2)    luaV_equalobj(NULL,t1,t2)


/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result).  Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/
#define luaV_fastget(L, t, k, slot, f) \
  (!ttistable(t)  \
   ? (slot = NULL, 0)  /* not a table; 'slot' is NULL and result is 0 */  \
   : (slot = f(hvalue(t), k),  /* else, do raw access */  \
      !ttisnil(slot)))  /* result not nil? */

/*
** standard implementation for 'gettable'
*/
#define luaV_gettable(L, t, k, v) { const TValue *slot; \
  if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
  else luaV_finishget(L,t,k,v,slot); }


/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
 * #define luaV_fastset(L, t, k, slot, f, v)：这是宏定义的开始，luaV_fastset宏接受六个参数：
 * - L：指向Lua状态的指针。
 * - t：要设置的表对象。
 * - k：键（index or key）。
 * - slot：用于存储在表中找到的槽（slot）的指针。
 * - f：用于在表中查找键的函数。
 * - v：要设置的值。
 * (!ttistable(t)：这是三元运算符的条件部分。ttistable(t)检查t是否是一个表（table）。如果t不是一个表，那么整个表达式的结果将是第一个分支。
 * ? (slot = NULL, 0)：如果t不是表，那么slot被设置为NULL，并且整个宏的结果为0（表示失败）。
 * :：这是三元运算符的分隔符，表示如果条件部分为假（即t是一个表），则执行冒号后面的代码。
 * (slot = f(hvalue(t), k),：如果t是表，slot被设置为f函数在表t中查找键k的结果。这里的hvalue(t)是获取t的值部分，它是一个表对象。
 * ttisnil(slot) ? 0：如果找到的槽slot是nil，那么整个宏的结果为0。
 * :：这是另一个三元运算符的分隔符，表示如果slot不是nil，执行后面的代码。
 * (luaC_barrierback(L, hvalue(t), v),：如果slot不是nil，调用luaC_barrierback函数来执行垃圾收集器的屏障操作。这个操作确保了在进行赋值之前，值v可以被正确地追踪。
 * setobj2t(L, cast(TValue *,slot), v),：然后调用setobj2t函数来将值v设置到表t的槽slot中。cast(TValue *,slot)将slot转换为TValue *类型。
 * 1：如果成功执行了上述操作，整个宏的结果为1（表示成功）。
 * 总结来说，luaV_fastset宏用于快速设置表项。
 * 如果给定的t是一个表并且对应的键k已经存在于表中，它将调用垃圾收集器的屏障，执行原始的赋值操作，然后返回1。
 * 如果t不是一个表或者键k不存在（即对应的槽是nil），它将返回0，并将slot设置为NULL或nil。
 * 这个宏被luaV_finishget函数使用，用于完成获取操作。
 * 如果宏返回1，表示没有创建新的表项，因此不需要使TM缓存失效。
*/
#define luaV_fastset(L, t, k, slot, f, v) \
  (!ttistable(t) \
   ? (slot = NULL, 0) \
   : (slot = f(hvalue(t), k), \
     ttisnil(slot) ? 0 \
     : (luaC_barrierback(L, hvalue(t), v), \
        setobj2t(L, cast(TValue *,slot), v), \
        1)))


#define luaV_settable(L, t, k, v) { const TValue *slot; \
  if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
    luaV_finishset(L,t,k,v,slot); }


LUAI_FUNC int luaV_equalobj(lua_State *L, const TValue *t1, const TValue *t2);

LUAI_FUNC int luaV_lessthan(lua_State *L, const TValue *l, const TValue *r);

LUAI_FUNC int luaV_lessequal(lua_State *L, const TValue *l, const TValue *r);

LUAI_FUNC int luaV_tonumber_(const TValue *obj, lua_Number *n);

LUAI_FUNC int luaV_tointeger(const TValue *obj, lua_Integer *p, int mode);

LUAI_FUNC void luaV_finishget(lua_State *L, const TValue *t, TValue *key,
                              StkId val, const TValue *slot);

LUAI_FUNC void luaV_finishset(lua_State *L, const TValue *t, TValue *key,
                              StkId val, const TValue *slot);

LUAI_FUNC void luaV_finishOp(lua_State *L);

LUAI_FUNC void luaV_execute(lua_State *L);

LUAI_FUNC void luaV_concat(lua_State *L, int total);

LUAI_FUNC lua_Integer luaV_div(lua_State *L, lua_Integer x, lua_Integer y);

LUAI_FUNC lua_Integer luaV_mod(lua_State *L, lua_Integer x, lua_Integer y);

LUAI_FUNC lua_Integer luaV_shiftl(lua_Integer x, lua_Integer y);

LUAI_FUNC void luaV_objlen(lua_State *L, StkId ra, const TValue *rb);

#endif
